#include "stdafx.h"
#include "cvxStroke.h"
#include "cvxSf.h"
#include <conio.h>

using cvx::Bw8UImage;
using cvx::Rgb8UImage;

/************************************************************************/
/* 
	CvxStroke
*/
/************************************************************************/

CvxStroke::CvxStroke(int w, int h)
{
	m_map = Mat(h, w, CV_8U, Scalar(0, 0, 0, 0));
	m_curIdx = 1;
//	m_curRect = cv::Rect(0, 0, 0, 0);
}

CvxStroke::~CvxStroke()
{

}


bool CvxStroke::SetStroke(const vector<cv::Point> &pathPts, int penWidth, int &curIdx)
{
	if (pathPts.size() < 2)
	{
		_cprintf("stroke set stroke, path pts size = %d\n", pathPts.size());
		return false;
	}
	curIdx = m_curIdx++;
	cv::polylines(m_map, pathPts, false, Scalar(curIdx, curIdx, curIdx, curIdx), penWidth);
	return true;
}
void CvxStroke::updateIdx()
{
	m_curIdx++;
}

bool CvxStroke::BlenderStroke(const vector<cv::Point> &pathPts, int penWidth, Mat &showImage)
{
	assert(!showImage.empty());
	assert(showImage.channels() == 3);
	if (pathPts.size() < 2)
	{
		_cprintf("stroke set stroke, path pts size = %d\n", pathPts.size());
		return false;
	}	
	int curIdx = m_curIdx;
	cv::polylines(m_map, pathPts, false, Scalar(curIdx, curIdx, curIdx, curIdx), penWidth);
	cv::Rect rect = CvxSF::GetBoundingBox(m_map.cols, m_map.rows, penWidth, pathPts, 4);
	Bw8UImage s_map(&m_map);
	Rgb8UImage show_img(&showImage);
	for (int y = rect.y; y<rect.y + rect.height; ++y)
	{
		for (int x = rect.x; x<rect.x + rect.width; ++x)
		{
			if (s_map[y][x] == curIdx)
			{
				show_img[y][x].b = 128 + show_img[y][x].b/2;				
			}
		}
	}

	//@todo just for test
	Mat pathMat(pathPts);
 	FileStorage fs("path.xml", FileStorage::WRITE );
 	fs << "pathPts" << pathMat;
	fs.release();

	return true;
}
void CvxStroke::testShowMap()
{
	Mat tmap = m_map.clone();
	tmap.convertTo(tmap, CV_8U, 255.0/m_curIdx);
	imshow("stroke map", tmap);
}



/************************************************************************/
/* 
	CvxQuadStroke
*/
/************************************************************************/

CvxQuadStroke::CvxQuadStroke(int w, int h, CvxQuadTree *pTree):CvxStroke(w, h)
{
//	m_curRect = cv::Rect(0, 0, 0, 0);
	m_quadMap = m_map.clone();
	m_pTree = pTree;
}
CvxQuadStroke::~CvxQuadStroke()
{

}

bool CvxQuadStroke::SetStroke(const vector<cv::Point> &pathPts, int penWidth, int &curIdx)
{
	if (pathPts.size() < 2)
	{
		_cprintf("stroke set stroke, path pts size = %d\n", pathPts.size());
		return false;
	}
	assert(m_pTree);

	//get the stroke area
	curIdx = m_curIdx;
	assert(curIdx >= 1 && curIdx <= 255);
	cv::polylines(m_map, pathPts, false, Scalar(curIdx, curIdx, curIdx, curIdx), penWidth);
	cv::Rect rect = CvxSF::GetBoundingBox(m_map.cols, m_map.rows, penWidth, pathPts, 4);

	//get quad tree stroke area
	Bw8UImage s_map(&m_map);
	Bw8UImage quad_map(&m_quadMap);
	for (int y = rect.y; y<rect.y + rect.height; ++y)
	{
		for (int x = rect.x; x<rect.x + rect.width; ++x)
		{
			if (s_map[y][x] == curIdx)
			{
				//avoid repeated set for same points
				if (quad_map[y][x] != curIdx)
				{
					QtNode *pNode = m_pTree->LocateNode(x, y);
					assert(pNode);
					if (pNode)
					{
						int sz = 1<<pNode->_level;
						int x_loc = pNode->_xLocCode;
						int y_loc = pNode->_yLocCode;
						if (sz != 1)
						{			
							cv::Rect r1 = cv::Rect(x_loc, y_loc, sz, sz);
							Mat m1 = m_quadMap(r1);
							m1 = Scalar(curIdx, curIdx, curIdx, curIdx);
						}
						else
						{
							unsigned char *p = m_quadMap.ptr(y_loc, x_loc);
							p[0] = curIdx;							
						}
					}
				}
			}
		}
	}
	return true;
}

bool CvxQuadStroke::updateNode(int x, int y, cv::Rect &rect)
{
	int curIdx = m_curIdx;
	QtNode *pNode = m_pTree->LocateNode(x, y);
	if (!pNode)
	{
		return false;
	}
	if (pNode)
	{
		int sz = 1<<pNode->_level;
		int x_loc = pNode->_xLocCode;
		int y_loc = pNode->_yLocCode;
		rect = cv::Rect(x_loc, y_loc, sz, sz);
		if (sz != 1)
		{			
			Mat m1 = m_quadMap(rect);
			m1 = Scalar(curIdx, curIdx, curIdx, curIdx);
		}
		else
		{
			unsigned char *p = m_quadMap.ptr(y_loc, x_loc);
			p[0] = curIdx;							
		}
	}
	return true;
}

void CvxQuadStroke::updateIdx()
{
	m_curIdx++;
}

bool CvxQuadStroke::isSetIdx(int x, int y)
{
	return m_quadMap.at<unsigned char>(y, x) == m_curIdx;

}


void CvxQuadStroke::testShowMap()
{
	Mat tmap = m_map.clone();
	tmap.convertTo(tmap, CV_8U, 255.0/m_curIdx);
	imshow("stroke map", tmap);

	Mat tquadmap = m_quadMap.clone();
	tquadmap.convertTo(tquadmap, CV_8U, 255.0/m_curIdx);
	imshow("quad stroke map", tquadmap);
}